home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / source.exe / POSIX / RM / RM.C < prev    next >
C/C++ Source or Header  |  1993-06-23  |  10KB  |  406 lines

  1. /*-
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifdef DF_POSIX /* DF_MSS */
  35. #include <misc.h>
  36. #include <bsdlib.h>
  37. #endif
  38. #ifndef _POSIX_SOURCE /* DF_MSS */
  39. _S_ISLNK(){}
  40. #endif
  41.  
  42. #ifndef lint
  43. char copyright[] =
  44. "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
  45.  All rights reserved.\n";
  46. #endif /* not lint */
  47.  
  48. #ifndef lint
  49. static char sccsid[] = "@(#)rm.c    4.26 (Berkeley) 3/10/91";
  50. #endif /* not lint */
  51.  
  52. #include <sys/cdefs.h>
  53.  
  54. #include <sys/types.h>
  55. #include <sys/stat.h>
  56.  
  57. #ifdef _POSIX_SOURCE /* DF_MSS */
  58. #include <errno.h>
  59. #else
  60. #include <sys/errno.h>
  61. #endif
  62.  
  63. #include <fts.h>
  64. #include <unistd.h>
  65. #include <stdio.h>
  66. #include <string.h>
  67. #include <stdlib.h>
  68.  
  69. int dflag, fflag, iflag, retval, stdin_ok;
  70.  
  71. #if WIN_NT
  72. extern char *user_from_uid __P((uid_t, int));
  73. extern char *group_from_gid __P((gid_t, int));
  74. extern int globulate __P((int, int, char **));
  75. extern void deglobulate __P((void));
  76. extern int globulated_argc;
  77. extern char **globulated_argv;
  78. pid_t ppid;
  79. int globulation;
  80. #endif
  81. void rmtree __P((char **)), rmfile __P((char **)), checkdot __P((char **));
  82. void error __P((char *, int)), usage __P((void));
  83. int check __P((char *, char *, struct stat *));
  84.  
  85. /*
  86.  * rm --
  87.  *    This rm is different from historic rm's, but is expected to match
  88.  *    POSIX 1003.2 behavior.  The most visible difference is that -f
  89.  *    has two specific effects now, ignore non-existent files and force
  90.  *     file removal.
  91.  */
  92.  
  93. int
  94. #if __STDC__
  95. main (int argc, char **argv)
  96. #else
  97. main(argc, argv)
  98.     int argc;
  99.     char **argv;
  100. #endif
  101. {
  102.     extern char *optarg;
  103.     extern int optind;
  104.     int ch, rflag;
  105.  
  106. #if WIN_NT
  107.     ppid = getppid();
  108.     if (ppid == (pid_t) 1) /* if parent is CMD.EXE */
  109.     {
  110.         globulation = globulate(1, argc, argv);
  111.         if (globulation == 0)
  112.         {
  113.             argc = globulated_argc;
  114.             argv = globulated_argv;
  115.         }
  116.     }
  117. #endif
  118.         rflag = 0;
  119.     while ((ch = getopt(argc, argv, "dfiRr")) != EOF)
  120.         switch(ch) {
  121.         case 'd':
  122.             dflag = 1;
  123.             break;
  124.         case 'f':
  125.             fflag = 1;
  126.             iflag = 0;
  127.             break;
  128.         case 'i':
  129.             fflag = 0;
  130.             iflag = 1;
  131.             break;
  132.         case 'R':
  133.         case 'r':            /* compatibility */
  134.             rflag = 1;
  135.             break;
  136.         case '?':
  137.         default:
  138.             usage();
  139.         }
  140.     argc -= optind;
  141.     argv += optind;
  142.  
  143.     if (argc < 1)
  144.         usage();
  145.  
  146.     checkdot(argv);
  147.     if (!*argv) {
  148. #if WIN_NT
  149.         if (ppid == (pid_t) 1 && globulation == 0)
  150.             deglobulate();
  151. #endif
  152.         exit(retval);
  153.     }
  154.  
  155.     stdin_ok = isatty(STDIN_FILENO);
  156.  
  157.     if (rflag)
  158.         rmtree(argv);
  159.     else
  160.         rmfile(argv);
  161. #if WIN_NT
  162.     if (ppid == (pid_t) 1 && globulation == 0)
  163.         deglobulate();
  164. #endif
  165.     return retval;
  166. }
  167.  
  168. void
  169. #if __STDC__
  170. rmtree (char **argv)
  171. #else
  172. rmtree(argv)
  173.     char **argv;
  174. #endif
  175. {
  176.     register FTS *fts;
  177.     register FTSENT *p;
  178.     register int needstat;
  179.  
  180.     /*
  181.      * Remove a file hierarchy.  If forcing removal (-f), or interactive
  182.      * (-i) or can't ask anyway (stdin_ok), don't stat the file.
  183.      */
  184.     needstat = !fflag && !iflag && stdin_ok;
  185.  
  186.     /*
  187.      * If the -i option is specified, the user can skip on the pre-order
  188.      * visit.  The fts_number field flags skipped directories.
  189.      */
  190. #define    SKIPPED    1
  191.  
  192.     if (!(fts = fts_open(argv,
  193.         needstat ? FTS_PHYSICAL : FTS_PHYSICAL|FTS_NOSTAT,
  194.         (int (*) __P((const FTSENT *, const FTSENT *)))NULL))) {
  195.         (void)fprintf(stderr, "rm: %s.\n", strerror(errno));
  196. #if WIN_NT
  197.         if (ppid == (pid_t) 1 && globulation == 0)
  198.             deglobulate();
  199. #endif
  200.         exit(EXIT_FAILURE);
  201.     }
  202.     while ((p = fts_read(fts)) != NULL) {
  203.         switch(p->fts_info) {
  204.         case FTS_DNR:
  205.         case FTS_ERR:
  206.             error(p->fts_path, errno);
  207. #if WIN_NT
  208.             if (ppid == (pid_t) 1 && globulation == 0)
  209.                 deglobulate();
  210. #endif
  211.             exit(EXIT_FAILURE);
  212.         /*
  213.          * FTS_NS: assume that if can't stat the file, it can't be
  214.          * unlinked.
  215.          */
  216.         case FTS_NS:
  217.             if (!needstat)
  218.                 break;
  219.             if (!fflag || errno != ENOENT)
  220.                 error(p->fts_path, errno);
  221.             continue;
  222.         /* Pre-order: give user chance to skip. */
  223.         case FTS_D:
  224.             if (iflag && !check(p->fts_path, p->fts_accpath,
  225.                 &p->fts_statb)) {
  226.                 (void)fts_set(fts, p, FTS_SKIP);
  227.                 p->fts_number = SKIPPED;
  228.             }
  229.             continue;
  230.         /* Post-order: see if user skipped. */
  231.         case FTS_DP:
  232.             if (p->fts_number == SKIPPED)
  233.                 continue;
  234.             break;
  235.         }
  236.  
  237.         if (!fflag &&
  238.             !check(p->fts_path, p->fts_accpath, &p->fts_statb))
  239.             continue;
  240.         /*
  241.          * If we can't read or search the directory, may still be
  242.          * able to remove it.  Don't print out the un{read,search}able
  243.          * message unless the remove fails.
  244.          */
  245.         if (p->fts_info == FTS_DP || p->fts_info == FTS_DNR) {
  246.             if (!rmdir(p->fts_accpath))
  247.                 continue;
  248.             if (errno == ENOENT) {
  249.                 if (fflag)
  250.                     continue;
  251.             } else if (p->fts_info != FTS_DP)
  252.                 (void)fprintf(stderr,
  253.                     "rm: unable to read %s.\n", p->fts_path);
  254.         } else if (!unlink(p->fts_accpath) || fflag && errno == ENOENT)
  255.             continue;
  256.         error(p->fts_path, errno);
  257.     }
  258. }
  259.  
  260. void
  261. #if __STDC__
  262. rmfile (char **argv)
  263. #else
  264. rmfile(argv)
  265.     char **argv;
  266. #endif
  267. {
  268.     register int df;
  269.     register char *f;
  270.     struct stat sb;
  271.  
  272.     df = dflag;
  273.     /*
  274.      * Remove a file.  POSIX 1003.2 states that, by default, attempting
  275.      * to remove a directory is an error, so must always stat the file.
  276.      */
  277.     while ((f = *argv++) != NULL) {
  278.         /* Assume if can't stat the file, can't unlink it. */
  279. #if _POSIX_SOURCE
  280.         if (stat(f, &sb)) {
  281. #else
  282.         if (lstat(f, &sb)) {
  283. #endif
  284.             if (!fflag || errno != ENOENT)
  285.                 error(f, errno);
  286.             continue;
  287.         }
  288.         if (S_ISDIR(sb.st_mode) && !df) {
  289.             (void)fprintf(stderr, "rm: %s: is a directory\n", f);
  290.             retval = EXIT_FAILURE;
  291.             continue;
  292.         }
  293.         if (!fflag && !check(f, f, &sb))
  294.             continue;
  295.         if ((S_ISDIR(sb.st_mode) ? rmdir(f) : unlink(f)) &&
  296.             (!fflag || errno != ENOENT))
  297.             error(f, errno);
  298.     }
  299. }
  300.  
  301. int
  302. #if __STDC__
  303. check (char *path, char *name, struct stat *sp)
  304. #else
  305. check(path, name, sp)
  306.     char *path, *name;
  307.     struct stat *sp;
  308. #endif
  309. {
  310.     register int first, ch;
  311. #if WIN_NT
  312.     char modep[15];
  313. #else
  314.     char modep[15], *user_from_uid(), *group_from_gid();
  315. #endif
  316.  
  317.     /* Check -i first. */
  318.     if (iflag)
  319.         (void)fprintf(stderr, "remove %s? ", path);
  320.     else {
  321.         /*
  322.          * If it's not a symbolic link and it's unwritable and we're
  323.          * talking to a terminal, ask.  Symbolic links are excluded
  324.          * because their permissions are meaningless.
  325.          */
  326.  
  327. #ifdef _POSIX_SOURCE /* DF_MSS */
  328.                 if (!stdin_ok || !access(name, W_OK))
  329. #else
  330.                 if (S_ISLNK(sp->st_mode) || !stdin_ok || !access(name, W_OK))
  331. #endif
  332.                 return(1);
  333.  
  334.         strmode(sp->st_mode, modep);
  335.         (void)fprintf(stderr, "override %s%s%s/%s for %s? ",
  336.             modep + 1, modep[9] == ' ' ? "" : " ",
  337.             user_from_uid(sp->st_uid, 0),
  338.             group_from_gid(sp->st_gid, 0), path);
  339.  
  340.     }
  341.     (void)fflush(stderr);
  342.  
  343.     first = ch = getchar();
  344.     while (ch != '\n' && ch != EOF)
  345.         ch = getchar();
  346.     return(first == 'y');
  347. }
  348.  
  349. #define ISDOT(a)    ((a)[0] == '.' && (!(a)[1] || (a)[1] == '.' && !(a)[2]))
  350. void
  351. #if __STDC__
  352. checkdot (char **argv)
  353. #else
  354. checkdot(argv)
  355.     char **argv;
  356. #endif
  357. {
  358.     register char *p, **t, **save;
  359.     int complained;
  360.  
  361.     complained = 0;
  362.     for (t = argv; *t;) {
  363.         if ((p = rindex(*t, '/')) != NULL)
  364.             ++p;
  365.         else
  366.             p = *t;
  367.         if (ISDOT(p)) {
  368.             if (!complained++)
  369.                 (void)fprintf(stderr,
  370.                 "rm: \".\" and \"..\" may not be removed.\n");
  371.             retval = EXIT_FAILURE;
  372.             for (save = t; (t[0] = t[1]) != NULL; ++t);
  373.             t = save;
  374.         } else
  375.             ++t;
  376.     }
  377. }
  378.  
  379. void
  380. #if __STDC__
  381. error (char *name, int val)
  382. #else
  383. error(name, val)
  384.     char *name;
  385.     int val;
  386. #endif
  387. {
  388.     (void)fprintf(stderr, "rm: %s: %s.\n", name, strerror(val));
  389.     retval = EXIT_FAILURE;
  390. }
  391.  
  392. void
  393. #if __STDC__
  394. usage (void)
  395. #else
  396. usage()
  397. #endif
  398. {
  399.     (void)fprintf(stderr, "usage: rm [-dfiRr] file ...\n");
  400. #if WIN_NT
  401.     if (ppid == (pid_t) 1 && globulation == 0)
  402.         deglobulate();
  403. #endif
  404.     exit(EXIT_FAILURE);
  405. }
  406.